/**
 * @file prv_rtk_class.h
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __PRV_RTK_CLASS_H__
#define __PRV_RTK_CLASS_H__

#include "prv_rtk_macro.h"
#include "prv_rtk_cpu.h"
#include "rtk_def.h"
#include "rtk.h"
#include "k_kit.h"
#include "heap.h"
#include "list/slist.h"
#include "list/dlist.h"
#include "list/flist.h"

#ifdef __cplusplus
extern "C"
{
#endif /* #ifdef __cplusplus */

struct rtk_thread_handle;

/**
 * @brief 位-值 映射结构，每一位对于一个数值，用于快速计算当前已记录的最大值
 */
struct rtk_prior_index
{
#if defined(__CC_ARM) || defined(__GNUC__)

    u32_t tab[(CONFIG_RTK_MAX_PRIORITY + 32) / 32]; // 就绪线程表的坐标
    u32_t tab_y;

#else // #if defined(__CC_ARM) || defined(__GNUC__)

    u8_t tab[(CONFIG_RTK_MAX_PRIORITY + 8) / 8]; // 就绪线程表的坐标
    u8_t tab_y;

#endif // #if defined(__CC_ARM) || defined(__GNUC__)
};

typedef void (*rtk_hook_fn)(void *arg);

typedef void (*rtk_list_fn)(struct rtk_thread_handle *thread_handle);

typedef flist_t rtk_list_t;

struct rtk_list_node
{
    flist_node_t node;
    rtk_list_fn state_remove; // 从原链表移除的函数
    rtk_list_fn state_insert; // 新的链表连接的函数
};

struct rtk_sem_handle
{
    dlist_t sig_list;
    size_t value;
    size_t max;
    u8_t type;        // @ref rtk_sem_type
    vu8_t wait_retry; // 仅作用于内部函数 _rtk_wait_memory() ，用于按预定的超时时间继续等待
};

struct rtk_mutex_handle
{
    struct rtk_thread_handle *hold_thread; // 当前成功取得访问的线程，用于使该线程的优先级继承被堵塞的线程的优先级
    struct rtk_mutex_handle *last_mutex;   // 指向上一层的互斥量
    size_t nest_incr;                      // 嵌套计数
    void *prev;                            // 记录锁定顺序，用于死锁预判
};

struct rtk_thread_handle
{
    void *pSP; // 保存线程的栈指针

    rtk_thread_t *thread_handle;

    char *name;
    void *stack_base;
    size_t stack_size;
    struct
    {
        rtk_hook_fn entry;    // 线程入口地址
        rtk_prior_t priority; // 优先级（0 为最低，CONFIG_RTK_MAX_PRIORITY 为最高。若输入为负值则表示优先级为 (CONFIG_RTK_MAX_PRIORITY + 1 + priority)）
        u8_t slice_ticks;     // 被轮换的时间（值为 0 时不被轮换）
    } control;

    // 状态记录
    volatile rtk_thread_state_t curr_state; // 线程当前状态
    rtk_prior_t curr_prior;                 // 当前优先级
    u8_t slice_count;                       // 轮换计时
    u8_t wait_forever;                      // 标记无限等待
    vu8_t obj_enable;                       // 用于特殊任务的使能
    int wakeup_tick;                        // 线程定时唤醒时间
    vuint flag;                             // 需要关中断的当前状态标记 @ref _RTK_THREAD_FLAG_HEAP _RTK_THREAD_FLAG_SYS _RTK_THREAD_FLAG_SEM

    /* 作为特殊任务的状态 */
    union
    {
        k_work_q_t work_q_handle;
        k_timer_q_t timer_q_handle;
    } obj;

    struct rtk_list_node state_node; // 线程状态链的节点
    slist_node_t critical_node;      // slist_critical 的节点
    slist_node_t active_node;        // slist_active, slist_delete 的节点
    dlist_node_t sig_node;           // sem->sig_list / blocked_list 的节点

    struct rtk_sem_handle *sem;     // 信号量
    struct rtk_mutex_handle *mutex; // 正在锁定的互斥量
    dlist_t blocked_list;           // 被互斥量堵塞的线程的链，用于查询优先级返回的依据信息

    slist_t slist_trace; // 用于跟踪调用接口

#if defined(CONFIG_RTK_STACK_CHECK)
    int stack_remain; // 记录了线程栈的剩余内存大小（字节）
#endif

#if (CONFIG_RTK_POSIX_ERRNO == 1)
    int posix_errno;
#endif
};

struct rtk_timer_handle
{
    slist_node_t timer_node; // slist_timer 的节点
    rtk_timer_t *timer_handle;
    rtk_work_t work_handle;
    const char *name;
    rtk_hook_fn route;
    void *arg;
    rtk_tick_t period;
    u8_t periodic;
};

/*************************************************************************
** 运行内存
*************************************************************************/
struct cm_rtk_struct
{
    size_t MemDetector_Head; // 内存监测值

    /* 标记 */
    bool stack_grow_up; // true -- 栈向上生长; false -- 栈向下生长

    /* 堆管理 */
    heap_t heap_handle;             // 自定义的堆
    heapk_t heapk_handle;           // 带索引的堆
    struct rtk_sem_handle heap_sem; // 当内存申请失败时，等待其他线程释放一些内存的信号

    /* scheduler */
    vuint nest_list;                 // 链接屏蔽计数
    vuint nest_sched;                // 调度器屏蔽计数
    vuint nest_int;                  // 中断屏蔽计数
    vuint flag_int;                  // 内部中断嵌套计数
    slist_t slist_critical;          // 由 _rtk_list_atomic() 使用的队列
    slist_t slist_active;            // 所有已创建的线程的队列
    slist_t slist_delete;            // 所有已待删除的线程的队列
    slist_node_t *active_node_index; // 作用于 rtk_thread_list_next()，列出当前的线程

    /* 线程状态链 */
    struct rtk_prior_index prior_index_pend;           // 记录就绪链中的优先级的位值表
    rtk_list_t list_pend[CONFIG_RTK_MAX_PRIORITY + 1]; // 就绪链
    rtk_list_t list_sleep;                             // 延时链

    /* 内置线程 */
    rtk_thread_t thread_idle;
    rtk_thread_t thread_mem_check;
    rtk_thread_t thread_timer;

    struct rtk_thread_handle *thread_from; // 仅由滴答时钟服务线程使用，记录正在被打断的原线程

    /* CPU使用率空闲记录 */
    struct
    {
        size_t idle_incr; // 运行空闲线程的计数器
        size_t curr_incr; // 当前获取到的空闲线程计数器的值
        size_t max_incr;  // 空闲线程计数器的最大值
        vu8_t pending;
    } cpu_log;

    int systime_early; // 记录了当前最接近的超时时间值，用于快速与 systime_tick 比较
    int systime_tick;  // 滴答时钟中断计数

    char name_buf[0x40]; // 句柄名的共享缓存

    void *heap_log; // 正在访问的堆，用于有效性检查时导致系统错误的断定

    size_t MemDetector_Tail; // 中断程序用穿栈顶的检测字
};

extern struct cm_rtk_struct *cm_rtk;
extern struct rtk_thread_handle *curr_thread_handle;          // 当前线程
extern struct rtk_thread_handle *volatile next_thread_handle; // 下个线程

/**
 * @file rtk_scheduler.c
 */
void _rtk_prior_set(struct rtk_prior_index *index, size_t lev);
void _rtk_prior_reset(struct rtk_prior_index *index, size_t lev);
size_t _rtk_prior_highest(struct rtk_prior_index *index);
void _rtk_scheduler_to_highest(void);
void _rtk_scheduler_do_swap(struct rtk_thread_handle *from, struct rtk_thread_handle *to);

/**
 * @file rtk_list.c
 */
/* 调度器接口（可在线程或中断模式下使用） */
void _rtk_list_atomic_yield(struct rtk_thread_handle *thread);
void _rtk_list_atomic_resume(struct rtk_thread_handle *thread);
void _rtk_list_atomic_pend(struct rtk_thread_handle *thread);
void _rtk_list_atomic_suspend(struct rtk_thread_handle *thread);
void _rtk_list_atomic_deleted(struct rtk_thread_handle *thread);
void _rtk_list_atomic_sleep(struct rtk_thread_handle *thread);
void _rtk_list_atomic_wait_sem(struct rtk_thread_handle *thread);
void _rtk_list_atomic_wait_mutex(struct rtk_thread_handle *thread);
void _rtk_list_atomic(struct rtk_thread_handle *thread, void (*list_insert_fn)(struct rtk_thread_handle *thread)); // 把任意一个线程插入到任意一个链表中

void _rtk_list_atomic_pend_timeup(void);

void _rtk_list_init_list(rtk_list_t *list);
void _rtk_list_init_node(struct rtk_list_node *node);
struct rtk_thread_handle *_rtk_list_peek_head(rtk_list_t *list);
struct rtk_thread_handle *_rtk_list_peek_tail(rtk_list_t *list);
struct rtk_thread_handle *_rtk_list_peek_next(struct rtk_list_node *node);
struct rtk_thread_handle *_rtk_list_peek_prev(struct rtk_list_node *node);
struct rtk_thread_handle *_rtk_list_take(rtk_list_t *list);
bool _rtk_list_next(rtk_list_t *list);

/**
 * @file rtk_semaphore.c
 */
void _rtk_sem_init(struct rtk_sem_handle *sem, size_t init_value, size_t max_value, rtk_sem_type type);
void *_rtk_wait_memory(void *(*fn)(void *func_handle, va_list arp), void *func_handle, struct rtk_sem_handle *sem, rtk_tick_t wait_ticks, ...);
void _rtk_sem_set_value(struct rtk_sem_handle *sem, size_t new_value);
rtk_err_t _rtk_sem_release(struct rtk_sem_handle *sem);
rtk_err_t _rtk_sem_take(struct rtk_sem_handle *sem, rtk_tick_t wait_ticks);

/**
 * @file rtk_mutex.c
 */
void _rtk_mutex_init(struct rtk_mutex_handle *mutex);
void _rtk_mutex_release_unlock(struct rtk_mutex_handle *mutex);

/**
 * @file rtk_service.c
 */
void _rtk_isr_tick(void);

void _rtk_service_switch_to_tick(void); // 切换到线程 _rtk_service_thread_idle() 并进入管理模式

void _rtk_service_thread_free(struct rtk_thread_handle *thread);

void _rtk_service_thread_idle(void *arg);

int  _rtk_service_stack_remain(struct rtk_thread_handle *thread);
bool _rtk_service_handle_is_valid(void *handle);

void _rtk_service_trace_entry(void *s, const char *func);
void _rtk_service_trace_exit(void *s);

void _rtk_service_isr_check_log(const char *func);
void _rtk_service_isr_check_sched(const char *func);
rtk_err_t _rtk_service_assert_check_handle(size_t ass_type, void *handle, const char *file, u32_t line, const char *func);
rtk_err_t _rtk_service_assert_check_thread(size_t ass_type, rtk_thread_t *thread_handle, const char *file, u32_t line, const char *func);

void *_rtk_name_malloc(const char *name, size_t size);

#ifdef __cplusplus
} /* extern "C" */
#endif /* #ifdef __cplusplus */

#endif
